{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Approximate Optimization Algorithm\n",
    "\n",
    "In this notebook we are going to show how to use the implementation of QAOA available in Aqua to obtain solutions to the MaxCut problem"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from qiskit import Aer, IBMQ\n",
    "from qiskit.aqua import aqua_globals, QuantumInstance\n",
    "from qiskit.aqua.algorithms import QAOA\n",
    "from qiskit.aqua.components.optimizers import *\n",
    "from qiskit.quantum_info import Pauli\n",
    "from qiskit.aqua.operators import WeightedPauliOperator\n",
    "from qiskit.providers.aer.noise import NoiseModel\n",
    "\n",
    "provider = IBMQ.load_account()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we define a function that from the coefficients of an Ising model creates the Hamiltonian for which we are going to find the ground state."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_operator(J,h,n):    \n",
    "    pauli_list = []\n",
    "\n",
    "    for (i,j) in J: # For each coefficient in J (couplings) we add a term J[i,j]Z_iZj\n",
    "        x_p = np.zeros(n, dtype=np.bool)\n",
    "        z_p = np.zeros(n, dtype=np.bool)\n",
    "        z_p[n-1-i] = True \n",
    "        z_p[n-1-j] = True\n",
    "        pauli_list.append([J[(i,j)],Pauli(z_p, x_p)])\n",
    "     \n",
    "    for i in h: # For each coefficient in h we add a term h[i]Z_i\n",
    "        x_p = np.zeros(n, dtype=np.bool)\n",
    "        z_p = np.zeros(n, dtype=np.bool)\n",
    "        z_p[n-1-i] = True\n",
    "        pauli_list.append([h[i],Pauli(z_p, x_p)])\n",
    "    \n",
    "    return WeightedPauliOperator(paulis=pauli_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we define the edges of the graph and obtain the Hamiltonian. For this graph, which is a cycle of length 5, the optimal solution gives a cost of -3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Edges of the graph\n",
    "\n",
    "J1 = {(0,1):1, (1,2):1, (2,3):1, (3,4):1, (4,0):1}\n",
    "h1 = {}\n",
    "n = 5\n",
    "\n",
    "# Hamiltonian\n",
    "\n",
    "q_op =get_operator(J1,h1,n) \n",
    "print(q_op)\n",
    "q_op.print_details()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are going to run 10 repetitions on the statevector simulator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rep = 10\n",
    "backend = Aer.get_backend('statevector_simulator')\n",
    "quantum_instance = QuantumInstance(backend)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We run QAOA with COBYLA as the classical optimizer and with optimization level $p = 1$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = 1\n",
    "val = 0\n",
    "for i in range(rep):\n",
    "    print(\"----- ITERATION \",i, \" ------\")\n",
    "    optimizer = COBYLA()\n",
    "    qaoa = QAOA(q_op, optimizer, p=p)\n",
    "    result = qaoa.run(quantum_instance)\n",
    "    print(\"Optimal value\", result['optimal_value'])\n",
    "    val+=result['optimal_value']\n",
    "print(\"----- AVERAGE -----\")\n",
    "print(\"Average value\",val/rep)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we increase $p$ to $2$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = 2\n",
    "val = 0\n",
    "for i in range(rep):\n",
    "    print(\"----- ITERATION \",i, \" ------\")\n",
    "    optimizer = COBYLA()\n",
    "    qaoa = QAOA(q_op, optimizer, p=p)\n",
    "    result = qaoa.run(quantum_instance)\n",
    "    print(\"Optimal value\", result['optimal_value'])\n",
    "    val+=result['optimal_value']\n",
    "print(\"----- AVERAGE -----\")\n",
    "print(\"Average value\",val/rep)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are going to run the algorithm with a backend which includes a noise model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rep = 10\n",
    "backendIBM = provider.get_backend('ibmq_ourense')\n",
    "noise_model = NoiseModel.from_backend(backendIBM)\n",
    "coupling_map = backendIBM.configuration().coupling_map\n",
    "basis_gates = noise_model.basis_gates\n",
    "backend = Aer.get_backend(\"qasm_simulator\")\n",
    "\n",
    "\n",
    "shots = 8192\n",
    "optimization_level = 3\n",
    "p = 1\n",
    "quantum_instance = QuantumInstance(backend, shots = shots, \n",
    "                                    optimization_level = optimization_level,\n",
    "                                    noise_model = noise_model,\n",
    "                                    basis_gates = basis_gates,\n",
    "                                    coupling_map = coupling_map)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = 1\n",
    "val = 0\n",
    "for i in range(rep):\n",
    "    print(\"----- ITERATION \",i, \" ------\")\n",
    "    optimizer = COBYLA()\n",
    "    qaoa = QAOA(q_op, optimizer, p=p)\n",
    "    result = qaoa.run(quantum_instance)\n",
    "    print(\"Optimal value\", result['optimal_value'])\n",
    "    val+=result['optimal_value']\n",
    "print(\"----- AVERAGE -----\")\n",
    "print(\"Average value\",val/rep)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
